﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using CutAways.Modeling;

namespace CutAways.Illustration
{
	partial class OcclusionGraphVisualizationForm : Form
	{
		private OcclusionGraph graph;
		private Dictionary<GeometricObject, Point> objectPositions;
		private Dictionary<GeometricObject, string> legend;

		public OcclusionGraphVisualizationForm(OcclusionGraph graph)
		{
			InitializeComponent();
			this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true);
			this.graph = graph;
			objectPositions = new Dictionary<GeometricObject, Point>();
			legend = new Dictionary<GeometricObject, string>();
			createObjectLayout();
			createLegend();
			this.Text = graph.Model.Name + " - Occlusion graph";
		}
		
		private void createObjectLayout()
		{
			int xOffset = 150;
			int yOffset = 50;
			int xStep = 200;
			int yStep = 80;

			for (int i = 0; i < graph.Layers.Count; i++)
				for (int j = 0; j < graph.Layers[i].Count; j++)
					objectPositions[graph.Layers[i][j]] = new Point(j * xStep + xOffset, i * yStep + yOffset);

			this.Width = xOffset + graph.Layers.Max(x => x.Count) * xStep;
			this.Height = yOffset + graph.Layers.Count * yStep;
		}

		private void createLegend()
		{
			foreach (GeometricObject o in objectPositions.Keys)
			{
				string text = o.Name;
				if (TextRenderer.MeasureText(text, new Font(FontFamily.GenericSansSerif, 10f)).Width > 100)
					text = makeItShorter(text);
				legend[o] = text;
			}
		}

		private string makeItShorter(string text)
		{
			string[] parts = text.Split(' ');
			if (parts.Length > 1)
				return parts[1];
			return text.Substring(0, 20) + "...";
		}
		
		protected override void OnPaint(PaintEventArgs e)
		{
			base.OnPaint(e);
			Graphics g = e.Graphics;
			g.DrawString(objectPositions.Keys.Count.ToString() + " nodes, " + graph.EdgeCount.ToString() + " edges", new Font(FontFamily.GenericSansSerif, 10f), Brushes.Black, 10f, 10f);
			drawEdges(g);
			foreach (GeometricObject o in objectPositions.Keys)
				drawGraphNode(g, o);
		}

		private void drawEdges(Graphics g)
		{
			Pen pen = new Pen(Brushes.Blue, 2f);
			pen.CustomEndCap = new System.Drawing.Drawing2D.AdjustableArrowCap(6f, 8f);
			Random rand = new Random(DateTime.Now.Second);
			foreach (GeometricObject parrent in objectPositions.Keys)
			{
				foreach (GeometricObject child in graph.GetSuccessorsOf(parrent))
				{
					Point start = objectPositions[parrent];
					Point end = objectPositions[child];
					start.Y += 10;
					end.Y -= 10;
					int width = TextRenderer.MeasureText(legend[child], new Font(FontFamily.GenericSansSerif, 10f)).Width;
					end.X += rand.Next(-width / 2, width / 2);
					g.DrawLine(pen, start, end);
				}
			}
		}

		private void drawGraphNode(Graphics g, GeometricObject o)
		{
			string text = legend[o];
			Font font = new Font(FontFamily.GenericSansSerif, 10f);
			Size size = TextRenderer.MeasureText(g, text, font);
			
			Rectangle rect = new Rectangle(objectPositions[o].X - size.Width / 2, objectPositions[o].Y - size.Height / 2, size.Width, size.Height);
			g.FillRectangle(new SolidBrush(Color.FromArgb(150, Color.LightYellow)), rect);
			g.DrawRectangle(Pens.Black, rect);
			g.DrawString(text, font, Brushes.Black, rect);
		}

		private void buttonOK_Click(object sender, EventArgs e)
		{
			this.Close();
		}
	}
}
